import csv, simplejson, logging
# define a Handler which writes INFO messages or higher to the sys.stderr
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
# set a format which is simpler for console use
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
# tell the handler to use this format
console.setFormatter(formatter)
# add the handler to the root logger
logging.getLogger('').addHandler(console)


def field_positions(text):
    '''
    Give a text, eg. 
    ;;Subcatchment   N-Imperv   N-Perv     S-Imperv   S-Perv     PctZero    RouteTo    PctRouted
    
    Give a list of field postion and start, end column position
    column 1, 15
    etc...
    '''
    pre = None
    fields = []
    for idx, c in enumerate(text):
        if pre is None:
            #the start of the text
            field=[0, 0]
            field[0] = idx
        else:
            if pre==' ':
                if c==' ':
                    pass
                else:
                    #start of a new field
                    #save last field
                    field[1] = idx -1
                    fields.append(list(field))
                    #start of a field
                    field[0] = idx
                    field[1] = -100 #default to -100
        pre = c
    if field[1]==-100:
        #add the last one
        field[1] = idx
        fields.append(field)
    
    return fields


def point2geojson(inp, out, title):
    unctions = []
    records = {}
    geojson = { "type": "FeatureCollection","features": []}
    features = []
    fields = inp[title]['fields']
    for row in inp[title]['rows']:
        p = dict(zip(fields, row))
        id_fld = fields[0]
        id_v = p[id_fld]
        records[id_v] = p
    for row in inp['[COORDINATES]']['rows']:
        p = dict(zip(fields, row))
        id_fld = fields[0]
        id_v = p[id_fld]
        if records.get(id_v):
            for k, v in p.items():
                if records[id_v].get(k):
                    pass
                else:
                    records[id_v][k] = v
            features.append({"type": "Feature", 'properties': records[id_v], "geometry": {"type": "Point", "coordinates": [float(x) for x in row[1:]]}})
    out = open(out, 'w')
    geojson['features'] = features
    out.write(simplejson.dumps(geojson))


def conduits2geojson(inp, out):
    unctions = []
    records = {}
    geojson = { "type": "FeatureCollection","features": []}
    features = []
    fields = inp['[CONDUITS]']['fields']
    for row in inp['[CONDUITS]']['rows']:
        p = dict(zip(fields, row))
        id_fld = fields[0]
        id_v = p[id_fld]
        records[id_v] = p
        

    fields = inp['[XSECTIONS]']['fields']
    for row in inp['[XSECTIONS]']['rows']:
        p = dict(zip(fields, row))
        id_fld = fields[0]
        id_v = p[id_fld]
        if records.get(id_v):
            for k, v in p.items():
                if records[id_v].get(k):
                    pass
                else:
                    records[id_v][k] = v
    fields = inp['[LOSSES]']['fields']
    for row in inp['[LOSSES]']['rows']:
        p = dict(zip(fields, row))
        id_fld = fields[0]
        id_v = p[id_fld]
        if records.get(id_v):
            for k, v in p.items():
                if records[id_v].get(k):
                    pass
                else:
                    records[id_v][k] = v

    

    #nodes list:
    nodes = {}
    for row in inp['[COORDINATES]']['rows']:
        nodes[row[0]] = [float(x) for x in row[1:3]]
    #vertices
    vertices = {}
    for row in inp['[VERTICES]']['rows']:
        vertices.setdefault(row[0], [])
        vertices[row[0]].append([float(x) for x in row[1:3]])
    
    for k, v in records.items():
        fnode = v['Inlet_Node']
        tnode = v['Outlet_Node']
        v_f = nodes.get(fnode)
        if not v_f:
            print fnode
            print v

        v_t = nodes.get(tnode)

        if not v_t:
            print tnode
            print v
        v_v = vertices.get(k)
        if v_v:
            g = [v_f] + [v_v] + [v_t]
        else:
            g = [v_f] + [v_t]

        features.append({"type": "Feature", 'properties': v, "geometry": {"type": "LineString", "coordinates": g}})
    out = open(out, 'w')
    geojson['features'] = features
    out.write(simplejson.dumps(geojson))
    
    

def subcatchment2json(inp, out):
    '''convert an inpObject into a geojson file'''
    subcatchments = []
    features = {}
    fields = inp['[SUBCATCHMENTS]']['fields']
    for row in inp['[SUBCATCHMENTS]']['rows']:
        properties = dict(zip(fields, row))
        features[properties['Name']] ={'properties': properties}
    fields = inp['[SUBAREAS]']['fields']
    for row in inp['[SUBAREAS]']['rows']:
        properties = dict(zip(fields, row))
        feature = features.get(properties[fields[0]])
        if feature:
            properties = dict(zip(fields, row))
            for fld, v in properties.items():
                if feature['properties'].get(fld):
                    pass
                else:
                    feature['properties'][fld] = v
    fields = inp['[INFILTRATION]']['fields']
    for row in inp['[INFILTRATION]']['rows']:
        properties = dict(zip(fields, row))
        feature = features.get(properties[fields[0]])
        if feature:
            properties = dict(zip(fields, row))
            for fld, v in properties.items():
                if feature['properties'].get(fld):
                    pass
                else:
                    features.get(properties[fields[0]])['properties'][fld] = v
    polygons = polygon2geometry(inp)
    for k, v in polygons.items():
        feature = features.get(k)
        if feature:
            features[k]['type'] = 'Feature'
            features[k]['geometry'] = {'type': 'Polygon', 'coordinates': [v]}
    
    out = open(out, 'w')
    fs = []

    geojson = {'type': 'FeatureCollection', 'features':[v for k, v in features.items()]}
    out.write(simplejson.dumps(geojson))
    out.close()
              

def polygon2geometry(inp):
    polygons = {}
    for row in inp['[Polygons]'.upper()]['rows']:
        polygons.setdefault(row[0], [])
        polygons[row[0]].append([float(x) for x in row[1:]])
    return polygons

        
        
        
def load_inp(fpath):
    '''read a swmm inp file
    fpath: the path to the *.inp file
    It assumes that the field names are available.
    return an inp object:
    {'[SUBAREAS]': {'fields': [fld1, fld2,..], 'rows': [[v1, v2...], [v1, v2, ...]}}
    '''
    f = open(fpath)
    inp = {}
    header = []
    fields = []
    rows = []
    title = None
    p_title = None
    for l in f:
        if l.strip().upper().startswith('['):
            #it is a new section
            title = l.strip().upper()
            
            #a new section, need to save the old section
            
            if len(header)==2:
                line1 = header[0]
                line2 = header[1]
                for idx1, idx2 in  field_positions(line2):
                    h1 = line1[idx1:idx2].strip().replace(';', '')
                    h2 = line2[idx1:idx2].strip().replace(';', '')
                    if h1: h = '%s_%s' % (h1, h2)
                    else: h = h2
                    fields.append(h)

            elif len(header)==1:
                line2 = header[0]
                fields = [x.replace(';', '') for x in line2.split()]
            
            if p_title:
                inp[p_title] = {'fields': fields, 'rows': rows}
                header = []
                fields = []
                rows = []
                
                
        elif l.strip().startswith(';;'):
            #it is the field names
            if l.strip().startswith(';;--'):
                pass
            else:
                header.append(l.strip())
        elif l.strip()=='':
            #skip empty lines
            pass
        else:
            if l.strip().startswith(';'):
                pass
            else:
                rows.append(l.strip().split())
        p_title = title

    inp[title] = {'fields': fields, 'rows': rows}
    return inp


#for k, v in load_inp('test.inp').items():
 #   print k, ':', len(v['rows'])
            
inp = load_inp('test.inp')
out = 'subcatchments.geojson'
subcatchment2json(inp, out)

out = 'junctions.geojson'
point2geojson(inp, out, '[JUNCTIONS]')
#junctions2json(inp, out)
#outfall2json(inp, 'outfalls.geojson')
point2geojson(inp, 'outfalls.geojson', '[OUTFALLS]')
conduits2geojson(inp, 'conduits.geojson')
